#include "jsnix.h"
#include <signal.h>
#include <semaphore.h>
#include <mqueue.h>

/* semaphore operate */
static int _os_sem_open(JSCTX *ctx)
{
	const char *name = __get_string_value(ctx, 0);
	int init_val = 0;
	if(__count(ctx)>1)
		init_val = __get_int_value(ctx, 1);

	__put_int_value(ctx, (int)sem_open(name, O_CREAT, 0666, init_val));

	return 1;
}

static int _os_sem_close(JSCTX *ctx)
{
	sem_t * sid = (sem_t*)__get_int_value(ctx, 0);
	__put_int_value(ctx, sem_close(sid));

	return 1;	
}

static int _os_sem_post(JSCTX *ctx)
{
	sem_t * sid = (sem_t*)__get_int_value(ctx, 0);
	__put_int_value(ctx, sem_post(sid));

	return 1;	
}
static int _os_sem_wait(JSCTX *ctx)
{
	sem_t * sid = (sem_t*)__get_int_value(ctx, 0);
	__put_int_value(ctx, sem_wait(sid));

	return 1;	
}

static int _os_sem_trywait(JSCTX *ctx)
{
	sem_t * sid = (sem_t*)__get_int_value(ctx, 0);
	__put_int_value(ctx, sem_trywait(sid));

	return 1;	
}

static int _os_sem_timedwait(JSCTX *ctx)
{
	sem_t * sid = (sem_t*)__get_int_value(ctx, 0);
	int cnt = __count(ctx);
	struct timespec ts;

       	if (clock_gettime(0, &ts) != -1)
	{	
		if(cnt > 1)
			ts.tv_sec += __get_int_value(ctx, 1);
	
		__put_int_value(ctx, sem_timedwait(sid, &ts));
	}
	else
		__put_int_value(ctx, -1);

	return 1;	
}

static int _os_sem_unlink(JSCTX *ctx)
{
	__put_int_value(ctx, sem_unlink(__get_string_value(ctx, 0)));
	return 1;
}

/** MQ */
static int _os_mq_open(JSCTX *ctx)
{
	const char *name = __get_string_value(ctx, 0);
	struct mq_attr attr, oattr;

	mqd_t qid = mq_open(name, O_CREAT|O_RDWR, 0666, NULL);
	if(mq_getattr(qid, &attr) == 0)
	{
		attr.mq_msgsize = 1024;
		mq_setattr(qid, &attr, &oattr);
	}
	__put_int_value(ctx, (int)qid);


	return 1;
}
static int _os_mq_close(JSCTX *ctx)
{
	__put_int_value(ctx, mq_close((mqd_t)__get_int_value(ctx, 0)));

	return 1;
}
static int _os_mq_send(JSCTX *ctx)
{
	mqd_t qid = __get_int_value(ctx, 0);
	const char *msg_ptr = __get_string_value(ctx, 1);
	size_t msg_len = strlen(msg_ptr);	
	unsigned msg_prio = 0;

	__put_int_value(ctx, mq_send(qid, msg_ptr, msg_len, msg_prio));

	return 1;
}

static int _os_mq_timedsend(JSCTX *ctx)
{
	mqd_t qid = __get_int_value(ctx, 0);
	const char *msg_ptr = __get_string_value(ctx, 1);
	size_t msg_len = strlen(msg_ptr);	
	unsigned msg_prio = 0;

        struct timespec ts;

        if (clock_gettime(0, &ts) != -1)
        {
                if(__count(ctx) > 2)
                        ts.tv_sec += __get_int_value(ctx, 1);

		__put_int_value(ctx, mq_timedsend(qid, msg_ptr, msg_len, msg_prio, &ts));
        }
        else
                __put_int_value(ctx, -1);

        return 1;
}

static int _os_mq_receive(JSCTX *ctx)
{
	mqd_t qid = (mqd_t)__get_int_value(ctx, 0);
	int msglen = __get_int_value(ctx, 1);
	unsigned prio;
	char buf[10240];	// Maximum msg length
	struct mq_attr attr;

	if(mq_getattr(qid, &attr) == 0)
	{
		printf("[MQ_ATTR] mq_maxmsg=%d, mq_msgsize=%d\n", attr.mq_maxmsg, attr.mq_msgsize);
	}

	if(msglen > 10240)
		msglen = 10240;

	int rc = mq_receive(qid, buf, msglen, NULL);
	int oid = __start_object(ctx);
	__put_int_prop(ctx, oid, "rc", rc);
	if(rc > 0){
		__put_lstring_prop(ctx, oid, "msg", buf, rc);
		// __put_int_prop(ctx, oid, "prio", prio);
	}

	return 1;
}

static int _os_mq_timedreceive(JSCTX *ctx)
{
        mqd_t qid = (mqd_t)__get_int_value(ctx, 0);
        int msglen = __get_int_value(ctx, 1);
        unsigned prio;
        char buf[10240]; // Maximum msg length
        if(msglen > 10240)
                msglen = 10240;
        struct timespec ts;
        if (clock_gettime(0, &ts) != -1)
        {
                if(__count(ctx) > 2)
                        ts.tv_sec += __get_int_value(ctx, 1);
	}

        int rc = mq_timedreceive(qid, buf, msglen, NULL, &ts);
        int oid = __start_object(ctx);
        __put_int_prop(ctx, oid, "rc", rc);
        if(rc > 0){
                __put_lstring_prop(ctx, oid, "msg", buf, rc);
        }

        return 1;
}
static int _os_mq_unlink(JSCTX *ctx)
{
	__put_int_value(ctx, mq_unlink(__get_string_value(ctx, 0)));
	return 1;
}


int load_ipc_module(JSCTX *ctx){

	__start_global_object(ctx, "ipc");
	/** semaphore */
	__register_function(ctx, "sem_open", _os_sem_open, 2);
	__register_function(ctx, "sem_close", _os_sem_close, 1);
	__register_function(ctx, "sem_post", _os_sem_post, 1);
	__register_function(ctx, "sem_wait", _os_sem_wait, 1);
	__register_function(ctx, "sem_trywait", _os_sem_trywait, 1);
	__register_function(ctx, "sem_timedwait", _os_sem_timedwait, 2);
	__register_function(ctx, "sem_unlink", _os_sem_unlink, 1);

	/** mq */
	__register_function(ctx, "mq_open", _os_mq_open, 1);
	__register_function(ctx, "mq_close", _os_mq_close, 1);
	__register_function(ctx, "mq_send", _os_mq_send, 2);
	__register_function(ctx, "mq_timedsend", _os_mq_timedsend, 3);
	__register_function(ctx, "mq_receive", _os_mq_receive, 2);
	__register_function(ctx, "mq_timedreceive", _os_mq_timedreceive, 3);
	__register_function(ctx, "mq_unlink", _os_mq_unlink, 1);

	__end_object(ctx)

	return 0;
}

